package com.wongoing.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 功能说明：泛型解析工具类
 * 修改说明：
 * @author 郑立兵 zhenglb@mesnac.com
 * @date 2017-3-24 上午11:20:20
 * @version V1.0
 */
public class GenericsUtils {
	
	/***
	 * 定义字符集
	 */
	private static char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7',   
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',   
        'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',   
        'y', 'z', 'A', 'B','C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',   
        'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',   
        'Z'};    //72个字符集   
	/***
	 * 通过反射，获得指定类的父类的泛型参数的实际类型
	 * @param clazz
	 * 			clazz 需要反射的类，改类必须继承泛型父类
	 * @param index
	 * 			泛型参数所在索引，从0开始
	 * @return
	 * 			泛型参数的实际类型，如果没有实现ParameterizedType接口，即不支持泛型，则直接返回<code>Object.class</code>
	 */
	@SuppressWarnings("rawtypes")
	public static Class getSupperClassGenericType(Class clazz, int index) {
		//得到泛型父类
		Type genType = clazz.getGenericSuperclass();
		//如果没有实现ParameterizedType接口，即不支持泛型，直接返回Object.class
		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}
		//返回表示此类型实际类型参数的Type对象的数组，数组里放的都是对应类型的Class，如BuyerServiceBean extends DaoSupport<Buyer,Contact>就返回Buyer和Contact类型
		Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class)params[index];
	}
	
	/***
	 * 通过反射，获得指定类的父类的泛型参数的实际类型
	 * @param clazz
	 * 			clazz 需要反射的类，改类必须继承泛型父类
	 * @return
	 * 			泛型参数的实际类型，如果没有实现ParameterizedType接口，即不支持泛型，则直接返回<code>Object.class</code>
	 */
	@SuppressWarnings("rawtypes")
	public static Class getSupperClassGenericType(Class clazz) {
		return getSupperClassGenericType(clazz, 0);
	}
	
	/***
	 * 通过反射,获得方法返回值泛型参数的实际类型. 如: public Map<String, Buyer> getNames(){} 
	 * @param method
	 * 			method 方法 
	 * @param index
	 * 			泛型参数所在索引,从0开始。
	 * @return
	 * 			泛型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，则直接返回<code>Object.class</code>
	 */
	@SuppressWarnings("rawtypes")
	public static Class getMethodGenericReturnType(Method method, int index) {  
        Type returnType = method.getGenericReturnType();  
        if (returnType instanceof ParameterizedType) {  
            ParameterizedType type = (ParameterizedType) returnType;  
            Type[] typeArguments = type.getActualTypeArguments();  
            if (index >= typeArguments.length || index < 0) {  
                throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
            }  
            return (Class) typeArguments[index];  
        }  
        return Object.class;  
    }
	
	/***
	 * 通过反射,获得方法返回值泛型参数的实际类型. 如: public Map<String, Buyer> getNames(){} 
	 * @param method
	 * 			method 方法 
	 * @return
	 * 			泛型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，则直接返回<code>Object.class</code>
	 */
	@SuppressWarnings("rawtypes")
	public static Class getMethodGenericReturnType(Method method) {  
        return getMethodGenericReturnType(method, 0);  
    }
	
	/***
	 * 通过反射,获得方法输入参数第index个输入参数的所有泛型参数的实际类型. 如: public void add(Map<String, Buyer> maps, List<String> names) {}
	 * @param method
	 * 			method 方法 
	 * @param index
	 * 			第几个输入参数
	 * @return
	 * 			输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口，即不支持泛型，则直接返回空集合
	 */
	@SuppressWarnings("rawtypes")
	public static List<Class> getMethodGenericParameterTypes(Method method, int index) {  
        List<Class> results = new ArrayList<Class>();  
        Type[] genericParameterTypes = method.getGenericParameterTypes();  
        if (index >= genericParameterTypes.length || index < 0) {  
            throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
        }  
        Type genericParameterType = genericParameterTypes[index];  
        if (genericParameterType instanceof ParameterizedType) {  
            ParameterizedType aType = (ParameterizedType) genericParameterType;  
            Type[] parameterArgTypes = aType.getActualTypeArguments();  
            for (Type parameterArgType : parameterArgTypes) {  
                Class parameterArgClass = (Class) parameterArgType;  
                results.add(parameterArgClass);  
            }  
            return results;  
        }  
        return results;  
    }
	
	/***
	 * 通过反射,获得方法输入参数第index个输入参数的所有泛型参数的实际类型. 如: public void add(Map<String, Buyer> maps, List<String> names) {}
	 * @param method
	 * 			method 方法 
	 * @return
	 * 			输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口，即不支持泛型，则直接返回空集合
	 */
	@SuppressWarnings("rawtypes")
	public static List<Class> getMethodGenericParameterTypes(Method method) {  
        return getMethodGenericParameterTypes(method, 0);  
    }
	
	/***
	 * 通过反射,获得Field泛型参数的实际类型. 如: public Map<String, Buyer> names; 
	 * @param field
	 * 			field 字段
	 * @param index
	 * 			泛型参数所在索引，从0开始。
	 * @return
	 * 			泛型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，则直接返回<code>Object.class</code>
	 */
	public static Class getFieldGenericType(Field field, int index) {  
        Type genericFieldType = field.getGenericType();  
  
        if (genericFieldType instanceof ParameterizedType) {  
            ParameterizedType aType = (ParameterizedType) genericFieldType;  
            Type[] fieldArgTypes = aType.getActualTypeArguments();  
            if (index >= fieldArgTypes.length || index < 0) {  
                throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));  
            }  
            return (Class) fieldArgTypes[index];  
        }  
        return Object.class;  
    }
	
	/***
	 * 通过反射,获得Field泛型参数的实际类型. 如: public Map<String, Buyer> names; 
	 * @param field
	 * 			field 字段
	 * @return
	 * 			泛型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，则直接返回<code>Object.class</code>
	 */
	public static Class getFieldGenericType(Field field) {  
        return getFieldGenericType(field, 0);  
    }
	
	/***
	 * 根据实体得到实体的所有属性
	 * @param objClass
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static String[] getColumnNames(String objClass) throws ClassNotFoundException {  
        String[] wageStrArray = null;  
        if (objClass != null) {  
            Class class1 = Class.forName(objClass);  
            Field[] field = class1.getDeclaredFields();// 这里便是获得实体Bean中所有属性的方法  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < field.length; i++) {// 这里不多说了  
                sb.append(field[i].getName());  
                // 这是分割符 是为了去掉最后那个逗号  
                // 比如 如果不去最后那个逗号 最后打印出来的结果是 "id,name,"  
                // 去了以后打印出来的是 "id,name"  
                if (i < field.length - 1) {  
                    sb.append(",");  
                }  
            }  
            // split(",");这是根据逗号来切割字符串使字符串变成一个数组  
            wageStrArray = sb.toString().split(",");  
            return wageStrArray;  
        } else {  
            return wageStrArray;  
        }  
    }
	
	public static Object[] field2Value(Field[] f, Object o) throws Exception {  
        Object[] value = new Object[f.length];  
        for (int i = 0; i < f.length; i++) {  
            value[i] = f[i].get(o);  
        }  
        return value;  
    }
	
//	public HttpSession getSession() {     
//        HttpSession session=null;  
//        ServletRequestAttributes attr = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();  
//        HttpSession contextSess = attr == null ? session : attr.getRequest().getSession(true);  
//        return contextSess;   
//    }
	
	/***
	 * 得到实体类
	 * @param objClass
	 * 			实体类包含包名
	 * @return
	 */
	public static  Class getEntityClass(String objClass) {
		
        Class entityClass = null;  
        try {  
        	entityClass = Class.forName(objClass);  
        } catch (ClassNotFoundException e) {              
        	e.printStackTrace();  
        }   
        return entityClass;  
    }
	
	/***
	 * 生成指定长度的随机密码
	 * @param passLength
	 * 			随机密码的长度
	 * @return
	 * 			返回生成的随机密码字符串
	 */
	public static String getPasswords(int passLength) {   
        String passwords = "";// 新建一个长度为指定需要密码个数的字符串数组   
        Random random = new Random();   
        StringBuilder password = new StringBuilder("");// 保存生成密码的变量   
        for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码   
    		password.append(chars[random.nextInt(62)]);// 为密码变量随机增加上面字符中的一个   
        }   
        passwords = password.toString();// 将生成出来的密码赋值给密码数组   
        return passwords;   
   }
}
